package org.cybzacg.convert.converters;

import org.cybzacg.convert.annotation.CopyProperty;
import org.cybzacg.convert.annotation.Converter;
import org.cybzacg.convert.cache.CopyCache;
import org.cybzacg.convert.config.CopyConfig;
import org.cybzacg.convert.core.AbstractTypeConverter;
import org.cybzacg.convert.enums.CopyMode;
import org.cybzacg.convert.enums.FieldFilterStrategy;
import org.cybzacg.convert.enums.ConversionType;
import org.cybzacg.convert.enums.ConversionPriority;
import org.cybzacg.convert.utils.ReflectionUtils;
import org.cybzacg.convert.context.ConversionContext;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 属性拷贝器
 * 提供高级属性拷贝功能，支持多种拷贝模式、字段过滤、类型转换
 * 
 * <p>
 * 主要功能：
 * <ul>
 * <li>创建新对象并拷贝字段：{@link #copy(Object, Class)}</li>
 * <li>在已存在对象间拷贝字段：{@link #copyProperties(Object, Object)}</li>
 * <li>静态便捷方法：{@link #copyTo(Object, Class)}</li>
 * <li>批量拷贝：{@link #batchCopy(List, Class)}</li>
 * <li>浅拷贝/深拷贝：{@link #shallowCopy(Object, Class)} /
 * {@link #deepCopy(Object, Class)}</li>
 * </ul>
 * 
 * <p>
 * 使用示例：
 * 
 * <pre>{@code
 * // 方式1：创建新对象并拷贝
 * UserDTO dto = PropertyCopier.copyTo(userEntity, UserDTO.class);
 * 
 * // 方式2：在已存在对象间拷贝
 * UserDTO dto = new UserDTO();
 * PropertyCopier.copyTo(userEntity, dto);
 * 
 * // 方式3：使用实例方法
 * PropertyCopier copier = new PropertyCopier();
 * UserDTO dto = copier.copy(userEntity, UserDTO.class);
 * 
 * // 方式4：自定义配置
 * CopyConfig config = CopyConfig.builder()
 *         .mode(CopyMode.DEEP)
 *         .excludeFields("password", "salt")
 *         .build();
 * UserDTO dto = PropertyCopier.copyTo(userEntity, UserDTO.class, config);
 * }</pre>
 * 
 * @author PropertyCopier Implementation
 * @version 4.0
 * @since 1.0.0
 */
@Converter(name = "PropertyCopier", priority = ConversionPriority.LOW, enabled = true)
public class PropertyCopier extends AbstractTypeConverter {

    /**
     * 静态默认实例，用于静态方法调用
     * 避免每次调用静态方法都创建新实例
     */
    private static final PropertyCopier DEFAULT_INSTANCE = new PropertyCopier();

    // 缓存实例
    private final CopyCache<String, Object> copyCache;

    // 字段过滤器缓存
    private final Map<String, List<Field>> fieldFilterCache = new ConcurrentHashMap<>();

    // 默认配置
    private final CopyConfig defaultConfig;

    /**
     * 构造函数
     */
    public PropertyCopier() {
        this(CopyConfig.createDefault());
    }

    /**
     * 构造函数
     * 
     * @param defaultConfig 默认配置
     */
    public PropertyCopier(CopyConfig defaultConfig) {
        super();
        this.defaultConfig = defaultConfig != null ? defaultConfig : CopyConfig.createDefault();
        this.copyCache = new CopyCache<>(
                this.defaultConfig.getCacheSize(),
                30 * 60 * 1000L, // 30分钟过期
                60 * 60 * 1000L, // 1小时访问过期
                true // 启用软引用
        );
    }

    /**
     * 基础拷贝方法
     * 
     * @param source     源对象
     * @param targetType 目标类型
     * @return 拷贝后的对象
     */
    public <T> T copy(Object source, Class<T> targetType) {
        return copy(source, targetType, defaultConfig);
    }

    /**
     * 带配置的拷贝方法
     * 
     * @param source     源对象
     * @param targetType 目标类型
     * @param config     拷贝配置
     * @return 拷贝后的对象
     */
    @SuppressWarnings("unchecked")
    public <T> T copy(Object source, Class<T> targetType, CopyConfig config) {
        if (source == null) {
            return null;
        }
        if (targetType == null) {
            throw new IllegalArgumentException("目标类型不能为null");
        }

        final CopyConfig finalConfig = config != null ? config : defaultConfig;

        // 验证配置
        CopyConfig.ValidationResult validation = finalConfig.validate();
        if (!validation.isValid()) {
            throw new IllegalArgumentException("配置验证失败: " + validation.getErrors());
        }

        // 检查缓存
        if (finalConfig.isEnableCache()) {
            String cacheKey = generateCacheKey(source, targetType, finalConfig);
            T cached = (T) copyCache.get(cacheKey);
            if (cached != null) {
                return cached;
            }
        }

        try {
            T result = doCopy(source, targetType, finalConfig, new HashSet<>());

            // 存入缓存
            if (finalConfig.isEnableCache() && result != null) {
                String cacheKey = generateCacheKey(source, targetType, finalConfig);
                copyCache.put(cacheKey, result);
            }

            return result;
        } catch (Exception e) {
            throw new RuntimeException("属性拷贝失败: " + e.getMessage(), e);
        }
    }

    /**
     * 对象间属性拷贝
     * 
     * @param source 源对象
     * @param target 目标对象
     */
    public void copyProperties(Object source, Object target) {
        copyProperties(source, target, defaultConfig);
    }

    /**
     * 带配置的对象间属性拷贝
     * 
     * @param source 源对象
     * @param target 目标对象
     * @param config 拷贝配置
     */
    public void copyProperties(Object source, Object target, CopyConfig config) {
        if (source == null || target == null) {
            return;
        }

        final CopyConfig finalConfig = config != null ? config : defaultConfig;

        try {
            doCopyProperties(source, target, finalConfig, new HashSet<>());
        } catch (Exception e) {
            throw new RuntimeException("属性拷贝失败: " + e.getMessage(), e);
        }
    }

    /**
     * 浅拷贝
     * 
     * @param source     源对象
     * @param targetType 目标类型
     * @return 浅拷贝结果
     */
    public <T> T shallowCopy(Object source, Class<T> targetType) {
        CopyConfig config = CopyConfig.createShallow();
        return copy(source, targetType, config);
    }

    /**
     * 深拷贝
     * 
     * @param source     源对象
     * @param targetType 目标类型
     * @return 深拷贝结果
     */
    public <T> T deepCopy(Object source, Class<T> targetType) {
        CopyConfig config = CopyConfig.createDeep();
        return copy(source, targetType, config);
    }

    /**
     * 克隆拷贝
     * 
     * @param source 源对象
     * @return 克隆结果
     */
    @SuppressWarnings("unchecked")
    public <T> T cloneCopy(T source) {
        if (source == null) {
            return null;
        }

        try {
            // 检查是否实现了Cloneable接口
            if (!(source instanceof Cloneable)) {
                throw new IllegalArgumentException("对象必须实现Cloneable接口");
            }

            Method cloneMethod = source.getClass().getMethod("clone");
            cloneMethod.setAccessible(true);
            return (T) cloneMethod.invoke(source);
        } catch (Exception e) {
            throw new RuntimeException("克隆失败: " + e.getMessage(), e);
        }
    }

    /**
     * 静态便捷方法：从源对象拷贝到目标类型
     * 使用默认配置进行字段拷贝
     * 
     * @param source      源对象（被拷贝的对象）
     * @param targetClass 目标类（拷贝到的类型）
     * @param <S>         源对象类型
     * @param <T>         目标对象类型
     * @return 拷贝后的目标对象
     */
    public static <S, T> T copyTo(S source, Class<T> targetClass) {
        if (source == null || targetClass == null) {
            return null;
        }
        return DEFAULT_INSTANCE.copy(source, targetClass);
    }

    /**
     * 静态便捷方法：从源对象拷贝到已存在的目标对象
     * 
     * @param source 源对象（被拷贝的对象）
     * @param target 目标对象（拷贝到的对象）
     * @param <S>    源对象类型
     * @param <T>    目标对象类型
     */
    public static <S, T> void copyTo(S source, T target) {
        if (source == null || target == null) {
            return;
        }
        DEFAULT_INSTANCE.copyProperties(source, target);
    }

    /**
     * 静态便捷方法：创建目标对象并从源对象拷贝字段
     * 支持自定义配置
     * 
     * <p>
     * 注意：由于需要自定义配置，此方法会创建新的PropertyCopier实例
     * 
     * @param source      源对象（被拷贝的对象）
     * @param targetClass 目标类（拷贝到的类型）
     * @param config      拷贝配置
     * @param <S>         源对象类型
     * @param <T>         目标对象类型
     * @return 拷贝后的目标对象
     */
    public static <S, T> T copyTo(S source, Class<T> targetClass, CopyConfig config) {
        if (source == null || targetClass == null) {
            return null;
        }
        // 自定义配置需要创建新实例，但这种情况应该较少
        PropertyCopier copier = new PropertyCopier(config);
        return copier.copy(source, targetClass, config);
    }

    /**
     * 创建一个新的目标对象实例并拷贝字段
     * 这是一个实例方法的别名，语义更清晰
     * 
     * @param source      源对象（被拷贝的对象）
     * @param targetClass 目标类（拷贝到的类型）
     * @param <T>         目标对象类型
     * @return 拷贝后的目标对象
     */
    public <T> T copyFieldsTo(Object source, Class<T> targetClass) {
        return copy(source, targetClass);
    }

    /**
     * 将源对象的字段拷贝到目标对象
     * 这是 copyProperties 的别名，语义更清晰
     * 
     * @param source 源对象（被拷贝的对象）
     * @param target 目标对象（拷贝到的对象）
     */
    public void copyFieldsTo(Object source, Object target) {
        copyProperties(source, target);
    }

    /**
     * 批量拷贝
     * 
     * @param sources    源对象列表
     * @param targetType 目标类型
     * @return 拷贝结果列表
     */
    public <T> List<T> batchCopy(List<?> sources, Class<T> targetType) {
        return batchCopy(sources, targetType, defaultConfig);
    }

    /**
     * 带配置的批量拷贝
     * 
     * @param sources    源对象列表
     * @param targetType 目标类型
     * @param config     拷贝配置
     * @return 拷贝结果列表
     */
    public <T> List<T> batchCopy(List<?> sources, Class<T> targetType, CopyConfig config) {
        if (sources == null || targetType == null) {
            return Collections.emptyList();
        }

        final CopyConfig finalConfig = config != null ? config : defaultConfig;

        if (finalConfig.isEnableParallelCopy() && sources.size() >= finalConfig.getParallelThreshold()) {
            // 并行拷贝 - 使用 Collectors.toList() 避免同步块
            return sources.parallelStream()
                    .filter(Objects::nonNull)
                    .map(source -> copy(source, targetType, finalConfig))
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
        } else {
            // 串行拷贝
            List<T> results = new ArrayList<>(sources.size());
            for (Object source : sources) {
                if (source != null) {
                    T result = copy(source, targetType, finalConfig);
                    if (result != null) {
                        results.add(result);
                    }
                }
            }
            return results;
        }
    }

    /**
     * 执行拷贝的核心逻辑
     */
    private <T> T doCopy(Object source, Class<T> targetType, CopyConfig config, Set<Object> visited) {
        if (source == null || targetType == null) {
            return null;
        }

        // 检查循环引用
        if (visited.contains(source)) {
            return null; // 或者抛出异常
        }
        visited.add(source);

        try {
            CopyMode mode = config.getDefaultMode();

            switch (mode) {
                case REFERENCE:
                    return targetType.isInstance(source) ? targetType.cast(source) : null;

                case CLONE:
                    return handleCloneCopy(source, targetType);

                case SHALLOW:
                case DEEP:
                default:
                    return handleFieldCopy(source, targetType, config, visited);
            }
        } finally {
            visited.remove(source);
        }
    }

    /**
     * 处理字段拷贝
     */
    private <T> T handleFieldCopy(Object source, Class<T> targetType, CopyConfig config, Set<Object> visited) {
        try {
            // 创建目标实例
            T target = ReflectionUtils.createInstance(targetType);
            if (target == null) {
                throw new RuntimeException("无法创建目标实例: " + targetType.getName());
            }

            // 拷贝属性
            doCopyProperties(source, target, config, visited);

            return target;
        } catch (Exception e) {
            throw new RuntimeException("字段拷贝失败: " + e.getMessage(), e);
        }
    }

    /**
     * 执行属性拷贝的核心逻辑
     */
    private void doCopyProperties(Object source, Object target, CopyConfig config, Set<Object> visited) {
        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();

        // 获取要拷贝的字段
        List<Field> fields = getFieldsForCopy(sourceClass, targetClass, config);

        for (Field sourceField : fields) {
            try {
                copyField(source, target, sourceField, config, visited);
            } catch (Exception e) {
                if (config.isFailOnMissingField() || config.isFailOnTypeMismatch()) {
                    throw new RuntimeException("字段拷贝失败: " + sourceField.getName(), e);
                }
                // 忽略错误，继续处理其他字段
            }
        }
    }

    /**
     * 拷贝单个字段
     */
    private void copyField(Object source, Object target, Field sourceField, CopyConfig config, Set<Object> visited)
            throws ReflectiveOperationException {

        // 检查字段是否可读
        if (!ReflectionUtils.isReadable(sourceField)) {
            return;
        }

        // 获取源字段值
        Object sourceValue;
        try {
            sourceValue = ReflectionUtils.getFieldValue(sourceField, source);
        } catch (ReflectionUtils.ReflectionException e) {
            throw new RuntimeException("无法获取字段值: " + sourceField.getName(), e);
        }

        // 检查是否忽略null值
        if (sourceValue == null && config.isIgnoreNullValues()) {
            return;
        }

        // 查找目标字段
        String targetFieldName = getTargetFieldName(sourceField, config);
        Field targetField = ReflectionUtils.getField(target.getClass(), targetFieldName);

        if (targetField == null) {
            if (config.isFailOnMissingField()) {
                throw new RuntimeException("目标字段不存在: " + targetFieldName);
            }
            return;
        }

        // 检查字段是否可写
        if (!ReflectionUtils.isWritable(targetField)) {
            return;
        }

        // 获取字段的CopyProperty注解
        CopyProperty sourceAnnotation = ReflectionUtils.getCopyPropertyAnnotation(sourceField);
        CopyProperty targetAnnotation = ReflectionUtils.getCopyPropertyAnnotation(targetField);

        // 检查是否为只读字段
        if ((sourceAnnotation != null && sourceAnnotation.readOnly()) ||
                (targetAnnotation != null && targetAnnotation.readOnly())) {
            return;
        }

        // 处理字段拷贝
        Object convertedValue = convertFieldValue(sourceValue, sourceField, targetField, config, visited);

        if (convertedValue != null || !config.isIgnoreNullValues()) {
            try {
                ReflectionUtils.setFieldValue(targetField, target, convertedValue);
            } catch (ReflectionUtils.ReflectionException e) {
                throw new RuntimeException("无法设置字段值: " + targetField.getName(), e);
            }
        }
    }

    /**
     * 转换字段值
     */
    private Object convertFieldValue(Object sourceValue, Field sourceField, Field targetField,
            CopyConfig config, Set<Object> visited) {

        if (sourceValue == null) {
            return null;
        }

        Class<?> sourceType = sourceField.getType();
        Class<?> targetType = targetField.getType();

        // 类型相同，需要根据拷贝模式决定是否创建新实例
        if (ReflectionUtils.isTypeCompatible(sourceType, targetType)) {
            // 对于深拷贝，即使是相同类型也需要创建新实例
            if (config.getDefaultMode() == CopyMode.DEEP && !isPrimitiveOrWrapper(sourceType)) {
                return doCopy(sourceValue, targetType, config, new HashSet<>(visited));
            }
            return sourceValue;
        }

        // 检查是否需要递归拷贝
        if (config.getDefaultMode().requiresRecursion() && !isPrimitiveOrWrapper(sourceType)) {
            // 对于深拷贝，需要创建新的实例
            if (config.getDefaultMode() == CopyMode.DEEP) {
                return doCopy(sourceValue, targetType, config, new HashSet<>(visited));
            }
            return doCopy(sourceValue, targetType, config, visited);
        }

        // 使用ConversionEngine进行类型转换
        try {
            // 这里可以集成ConversionEngine
            return convertType(sourceValue, targetType);
        } catch (Exception e) {
            if (config.isFailOnTypeMismatch()) {
                throw new RuntimeException("类型转换失败: " + sourceType + " -> " + targetType, e);
            }
            return null;
        }
    }

    /**
     * 获取目标字段名
     */
    private String getTargetFieldName(Field sourceField, CopyConfig config) {
        CopyProperty annotation = ReflectionUtils.getCopyPropertyAnnotation(sourceField);
        if (annotation != null && !annotation.name().isEmpty()) {
            return annotation.name();
        }
        return sourceField.getName();
    }

    /**
     * 获取用于拷贝的字段列表
     */
    private List<Field> getFieldsForCopy(Class<?> sourceClass, Class<?> targetClass, CopyConfig config) {
        // 构建包含字段配置的缓存键
        StringBuilder cacheKeyBuilder = new StringBuilder();
        cacheKeyBuilder.append(sourceClass.getName())
                .append(":").append(targetClass.getName())
                .append(":").append(config.getFilterStrategy().getCode());

        // 添加字段配置到缓存键
        if (config.getFilterStrategy() == FieldFilterStrategy.INCLUDE_ONLY) {
            cacheKeyBuilder.append(":include:").append(config.getIncludedFields().toString());
        } else if (config.getFilterStrategy() == FieldFilterStrategy.EXCLUDE) {
            cacheKeyBuilder.append(":exclude:").append(config.getExcludedFields().toString());
        }

        String cacheKey = cacheKeyBuilder.toString();

        return fieldFilterCache.computeIfAbsent(cacheKey, key -> {
            List<Field> sourceFields = ReflectionUtils.getAllFields(sourceClass);
            List<Field> targetFields = ReflectionUtils.getAllFields(targetClass);

            // 应用字段过滤策略
            return applyFieldFilter(sourceFields, targetFields, config);
        });
    }

    /**
     * 应用字段过滤策略
     */
    private List<Field> applyFieldFilter(List<Field> sourceFields, List<Field> targetFields, CopyConfig config) {
        FieldFilterStrategy strategy = config.getFilterStrategy();

        switch (strategy) {
            case INCLUDE_ONLY:
                return filterFields(sourceFields, targetFields, config.getIncludedFields(), true);

            case EXCLUDE:
                return filterFields(sourceFields, targetFields, config.getExcludedFields(), false);

            case ANNOTATION_BASED:
                return filterFieldsByAnnotation(sourceFields, targetFields, config);

            case PATTERN_BASED:
                return filterFieldsByPattern(sourceFields, targetFields, config);

            default:
                // 默认策略：只拷贝目标类中存在的字段
                Set<String> targetFieldNames = targetFields.stream()
                        .map(Field::getName)
                        .collect(Collectors.toSet());

                return sourceFields.stream()
                        .filter(field -> targetFieldNames.contains(field.getName()))
                        .collect(Collectors.toList());
        }
    }

    /**
     * 根据字段名过滤
     */
    private List<Field> filterFields(List<Field> sourceFields, List<Field> targetFields,
            Set<String> fieldNames, boolean include) {
        Set<String> targetFieldNames = targetFields.stream()
                .map(Field::getName)
                .collect(Collectors.toSet());

        return sourceFields.stream()
                .filter(field -> {
                    String fieldName = field.getName();
                    boolean hasTarget = targetFieldNames.contains(fieldName);

                    // 如果是包含策略但没有指定包含字段，则包含所有匹配的字段
                    if (include && fieldNames.isEmpty()) {
                        return hasTarget;
                    }

                    return include ? fieldNames.contains(fieldName) && hasTarget
                            : !fieldNames.contains(fieldName) && hasTarget;
                })
                .collect(Collectors.toList());
    }

    /**
     * 根据注解过滤字段
     */
    private List<Field> filterFieldsByAnnotation(List<Field> sourceFields, List<Field> targetFields,
            CopyConfig config) {
        Set<String> targetFieldNames = targetFields.stream()
                .map(Field::getName)
                .collect(Collectors.toSet());

        return sourceFields.stream()
                .filter(sourceField -> {
                    // 检查包含注解
                    for (Class<? extends java.lang.annotation.Annotation> annotationClass : config
                            .getIncludeAnnotations()) {
                        if (ReflectionUtils.hasAnnotation(sourceField, annotationClass)) {
                            return targetFieldNames.contains(sourceField.getName());
                        }
                    }

                    // 检查排除注解
                    for (Class<? extends java.lang.annotation.Annotation> annotationClass : config
                            .getExcludeAnnotations()) {
                        if (ReflectionUtils.hasAnnotation(sourceField, annotationClass)) {
                            return false;
                        }
                    }

                    return targetFieldNames.contains(sourceField.getName());
                })
                .collect(Collectors.toList());
    }

    /**
     * 根据模式过滤字段
     */
    private List<Field> filterFieldsByPattern(List<Field> sourceFields, List<Field> targetFields, CopyConfig config) {
        Set<String> targetFieldNames = targetFields.stream()
                .map(Field::getName)
                .collect(Collectors.toSet());

        return sourceFields.stream()
                .filter(sourceField -> {
                    String fieldName = sourceField.getName();

                    // 检查包含模式
                    for (Pattern pattern : config.getIncludePatterns()) {
                        if (pattern.matcher(fieldName).matches()) {
                            return targetFieldNames.contains(fieldName);
                        }
                    }

                    // 检查排除模式
                    for (Pattern pattern : config.getExcludePatterns()) {
                        if (pattern.matcher(fieldName).matches()) {
                            return false;
                        }
                    }

                    return targetFieldNames.contains(fieldName);
                })
                .collect(Collectors.toList());
    }

    /**
     * 处理克隆拷贝
     */
    @SuppressWarnings("unchecked")
    private <T> T handleCloneCopy(Object source, Class<T> targetType) {
        if (source instanceof Cloneable) {
            try {
                Method cloneMethod = source.getClass().getMethod("clone");
                cloneMethod.setAccessible(true);
                Object cloned = cloneMethod.invoke(source);
                return targetType.isInstance(cloned) ? targetType.cast(cloned) : null;
            } catch (Exception e) {
                throw new RuntimeException("克隆失败: " + e.getMessage(), e);
            }
        }
        return null;
    }

    /**
     * 生成缓存键
     */
    private String generateCacheKey(Object source, Class<?> targetType, CopyConfig config) {
        return source.getClass().getName() + ":" + targetType.getName() + ":" +
                source.hashCode() + ":" + config.hashCode();
    }

    /**
     * 检查是否为基本类型或包装类型
     */
    private boolean isPrimitiveOrWrapper(Class<?> type) {
        return type.isPrimitive() ||
                type == String.class ||
                type == Boolean.class ||
                type == Character.class ||
                type == Byte.class ||
                type == Short.class ||
                type == Integer.class ||
                type == Long.class ||
                type == Float.class ||
                type == Double.class;
    }

    /**
     * 类型转换（简单实现，可以集成ConversionEngine）
     */
    private Object convertType(Object source, Class<?> targetType) {
        if (source == null) {
            return null;
        }

        // 这里可以实现更复杂的类型转换逻辑
        // 或者集成现有的ConversionEngine
        return source; // 简化实现
    }

    /**
     * 获取缓存统计信息
     */
    public CopyCache.CacheStatistics getCacheStatistics() {
        return copyCache.getStatistics();
    }

    /**
     * 清除缓存
     */
    public void clearCache() {
        copyCache.clear();
        fieldFilterCache.clear();
    }

    /**
     * 关闭资源
     */
    public void shutdown() {
        copyCache.shutdown();
        fieldFilterCache.clear();
    }

    @Override
    protected <T> T doConvert(Object source, Class<T> targetType, T defaultValue, ConversionContext context)
            throws Exception {
        return copy(source, targetType, defaultConfig);
    }

    @Override
    public Class<?> getSupportedType() {
        return Object.class;
    }

    @Override
    protected ConversionType getConversionType() {
        return ConversionType.OBJECT;
    }
}
